﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using Microsoft.SharePoint.Administration;
using System.Collections.ObjectModel;
using System.Xml;
using Microsoft.SharePoint;
using System.Reflection;

namespace Wilke.SharePoint.Tools
{
    internal class WebConfigFileChanges
    {
        internal SortedList WebConfigAttrChanges;
        internal SortedList WebConfigChildNodes;
        internal SortedList WebConfigSections;

        internal WebConfigFileChanges()
        {
            this.WebConfigChildNodes = new SortedList();
            this.WebConfigAttrChanges = new SortedList();
            this.WebConfigSections = new SortedList();
        }

        internal void AddListModifications(Collection<WebConfigModification> webConfigModifications)
        {
            foreach (WebConfigModification modification in webConfigModifications)
            {
                string key = modification.Path + "/" + modification.Name;
                WebConfigModification modification2 = null;
                switch (modification.Type)
                {
                    case WebConfigModificationType.EnsureChildNode:
                        {
                            modification2 = (WebConfigModification)this.WebConfigChildNodes[key];
                            if (modification2 == null)
                            {
                                break;
                            }
                            if (modification.Sequence >= modification2.Sequence)
                            {
                                this.WebConfigChildNodes[key] = modification;
                            }
                            continue;
                        }
                    case WebConfigModificationType.EnsureAttribute:
                        {
                            modification2 = (WebConfigModification)this.WebConfigAttrChanges[key];
                            if (modification2 == null)
                            {
                                goto Label_00E6;
                            }
                            if (modification.Sequence >= modification2.Sequence)
                            {
                                this.WebConfigAttrChanges[key] = modification;
                            }
                            continue;
                        }
                    case WebConfigModificationType.EnsureSection:
                        {
                            modification2 = (WebConfigModification)this.WebConfigSections[key];
                            if (modification2 == null)
                            {
                                this.WebConfigSections.Add(key, modification);
                            }
                            continue;
                        }
                    default:
                        {
                            continue;
                        }
                }
                this.WebConfigChildNodes.Add(key, modification);
                continue;
            Label_00E6:
                this.WebConfigAttrChanges.Add(key, modification);
            }
        }

        internal void ApplyModificationsWebConfigXmlDocument(XmlDocument xdWebConfig)
        {
            WebConfigHelper.EnsureSystemWebServerSection(xdWebConfig);

            #region EnsureSection

            foreach (WebConfigModification modification in this.WebConfigSections.Values)
            {
                XmlNode node = xdWebConfig.SelectSingleNode(modification.Path);
                if (node == null)
                {
                    throw new Exception(String.Format("Following node was not found in xml document: '{0}'.", modification.Path));
                }
                if ((node != null) && (node.SelectSingleNode(modification.Name) == null))
                {
                    StringBuilder builder = new StringBuilder();
                    builder.Append("<");
                    builder.Append(modification.Name);
                    builder.Append("></");
                    builder.Append(modification.Name);
                    builder.Append(">");
                    node.InnerXml = node.InnerXml + builder.ToString();
                }
            }

            #endregion

            #region EnsureChildNode
            
            foreach (WebConfigModification modification2 in this.WebConfigChildNodes.Values)
            {
                XmlNode node2 = xdWebConfig.SelectSingleNode(modification2.Path);
                if (node2 == null)
                {
                    throw new Exception(String.Format("Following node was not found in xml document: '{0}'.", modification2.Path));
                }
                if (node2.SelectSingleNode(modification2.Name) == null)
                {
                    if (modification2.Value.Length == 0)
                    {
                        throw new Exception(String.Format("Value property for node '{0}'can not be empty.: '{0}'.", modification2.Name));
                    }
                    node2.InnerXml = node2.InnerXml + modification2.Value;
                    continue;
                }
            }

            #endregion

            #region EnsureAttributes

            foreach (WebConfigModification modification3 in this.WebConfigAttrChanges.Values)
            {
                XmlElement element = xdWebConfig.SelectSingleNode(modification3.Path) as XmlElement;
                if (element == null)
                {
                    throw new Exception(String.Format("Following node was not found in xml document: '{0}'.", modification3.Path));
                }
                if (element != null)
                {
                    //modification3.PreviousAttrValue = element.GetAttribute(modification3.Name);
                    modification3.PreviousAttributeValue = element.GetAttribute(modification3.Name);
                    element.SetAttribute(modification3.Name, modification3.Value);
                }
            }

            #endregion
        }

        internal bool Equals(WebConfigFileChanges webcfg)
        {
            if (!this.SortedListCompare(this.WebConfigSections, webcfg.WebConfigSections))
            {
                return false;
            }
            if (!this.SortedListCompare(this.WebConfigChildNodes, webcfg.WebConfigChildNodes))
            {
                return false;
            }
            if (!this.SortedListCompare(this.WebConfigAttrChanges, webcfg.WebConfigAttrChanges))
            {
                return false;
            }
            return true;
        }
  
        internal void RebuildListModifications(Collection<WebConfigModification> webConfigModifications)
        {
            this.WebConfigChildNodes.Clear();
            this.WebConfigAttrChanges.Clear();
            this.AddListModifications(webConfigModifications);
        }

        internal void RemoveModificationsWebConfigXmlDocument(XmlDocument xdWebConfig)
        {
            if (this.WebConfigChildNodes != null)
            {
                IList valueList = this.WebConfigChildNodes.GetValueList();
                for (int i = this.WebConfigChildNodes.Count - 1; i >= 0; i--)
                {
                    WebConfigModification modification = (WebConfigModification)valueList[i];
                    XmlNode node = xdWebConfig.SelectSingleNode(modification.Path);
                    if (node != null)
                    {
                        XmlNode oldChild = node.SelectSingleNode(modification.Name);
                        if (oldChild != null)
                        {
                            node.RemoveChild(oldChild);
                        }
                    }
                }
            }
            if (this.WebConfigAttrChanges != null)
            {
                foreach (WebConfigModification modification2 in this.WebConfigAttrChanges.Values)
                {
                    XmlElement element = xdWebConfig.SelectSingleNode(modification2.Path) as XmlElement;
                    if (element != null)
                    {
                        string previousAttributeValue = modification2.PreviousAttributeValue;

                        if (previousAttributeValue.Length != 0)
                        {
                            element.SetAttribute(modification2.Name, previousAttributeValue);
                        }
                        else
                        {
                            element.RemoveAttribute(modification2.Name);
                        }
                    }
                }
            }
        }

        private bool SortedListCompare(SortedList lst1, SortedList lst2)
        {
            if (lst1.Count != lst2.Count)
            {
                return false;
            }
            IList valueList = lst1.GetValueList();
            IList list2 = lst2.GetValueList();
            for (int i = 0; i < lst1.Count; i++)
            {
                WebConfigModification modification = (WebConfigModification)valueList[i];
                WebConfigModification modification2 = (WebConfigModification)list2[i];
                if (!modification.Equals(modification2))
                {
                    return false;
                }
            }
            return true;
        }
    }
}